//
//  PBETexturePVR.cpp
//  pork-belly-engine
//
//  Created by Park Han Young on 11. 11. 12..
//  Copyright (c) 2011 __MyCompanyName__. All rights reserved.
//

#include "PBETexturePVR.h"
#include <OpenGLES/ES1/glext.h>

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdint.h>

#define ERROR_POINT(message)	printf("ERROR POINT: %s(%d) - %s, %s", __FILE__, __LINE__, __FUNCTION__, message)
#define MAX(A,B)	((A) > (B) ? (A) : (B))

using namespace PBEGraphics;

enum
{
	kPVRTextureFlagTypePVRTC_2 = 24,
	kPVRTextureFlagTypePVRTC_4
};

typedef struct _PVRTexHeader
{
	uint32_t headerLength;
	uint32_t height;
	uint32_t width;
	uint32_t numMipmaps;
	uint32_t flags;
	uint32_t dataLength;
	uint32_t bpp;
	uint32_t bitmaskRed;
	uint32_t bitmaskGreen;
	uint32_t bitmaskBlue;
	uint32_t bitmaskAlpha;
	uint8_t  pvrTag[4];
	uint32_t numSurfs;
} PVRTexHeader;

void TexturePVR::load(const char* filename)
{
	FILE* pFile = fopen(filename, "rb");
	uint32_t filesize = 0;
	uint8_t* pdata;
	
	fseek(pFile, 0, SEEK_END);
	filesize = ftell(pFile);
	fseek(pFile, 0, SEEK_SET);
	pdata = (uint8_t*)malloc(sizeof(uint8_t) * filesize);
	fread(pdata, sizeof(uint8_t), filesize, pFile);
	fclose(pFile);
	
	PVRTexHeader* pHeader = (PVRTexHeader*)pdata;

	if(strncmp((const char*)pHeader->pvrTag, "PVR!", 4) != 0) ERROR_POINT("This is not PVR format.");
	
	uint32_t formatflags = pHeader->flags & 0xFF;
	uint32_t m_width = 0, m_height = 0;
	GLenum m_internalformat = 0;
	bool m_hasAlpha = false;
	
	uint8_t* imageBytes = NULL;
	uint32_t imageLength = 0;
	uint32_t imageOffset = 0, imageSize = 0;
	uint32_t blockSize = 0, widthBlocks = 0, heightBlocks = 0;
	uint32_t width = 0, height = 0, bpp = 4;
	
	if(formatflags == kPVRTextureFlagTypePVRTC_4 || formatflags == kPVRTextureFlagTypePVRTC_2)
	{
		if(formatflags == kPVRTextureFlagTypePVRTC_4)
			m_internalformat = GL_COMPRESSED_RGBA_PVRTC_4BPPV1_IMG;
		else if(formatflags == kPVRTextureFlagTypePVRTC_2)
			m_internalformat = GL_COMPRESSED_RGBA_PVRTC_2BPPV1_IMG;
		
		m_width = width = pHeader->width;
		m_height = height = pHeader->height;
		
		if(pHeader->bitmaskAlpha)
			m_hasAlpha = true;
		
		imageLength = pHeader->dataLength;
		imageBytes = pdata + sizeof(PVRTexHeader);
		
		uint32_t count = 0;
		
		while(imageOffset < imageLength)
		{
			if (formatflags == kPVRTextureFlagTypePVRTC_4)
			{
				blockSize = 4 * 4; // Pixel by pixel block size for 4bpp
				widthBlocks = width / 4;
				heightBlocks = height / 4;
				bpp = 4;
			}
			else
			{
				blockSize = 8 * 4; // Pixel by pixel block size for 2bpp
				widthBlocks = width / 8;
				heightBlocks = height / 4;
				bpp = 2;
			}
			
			if (widthBlocks < 2)
				widthBlocks = 2;
			if (heightBlocks < 2)
				heightBlocks = 2;
			
			imageSize = widthBlocks * heightBlocks * ((blockSize  * bpp) / 8);
			
			glCompressedTexImage2D(GL_TEXTURE_2D, count, m_internalformat, width, height, 0, imageSize, imageBytes+imageOffset);
			
			imageOffset += imageSize;
			
			width = MAX(width >> 1, 1);
			height = MAX(height >> 1, 1);
			
			count++;
		}
	}

	free(pdata);
}
